<template>
  <v-menu-collapse-transition>
    <ul class="v-side-menu"
      :key="+collapse"
      :class="{
        'v-side-menu--collapse': collapse
      }"
      role="menubar"
    >
      <slot></slot>
    </ul>
  </v-menu-collapse-transition>
</template>

<script>
  import { addClass, removeClass, hasClass } from '@/vuego/utils/dom';

  export default {
    name: 'VSideMenu',
    componentName: 'VSideMenu',
    provide() {
      return {
        rootMenu: this,
      };
    },

    components: {
      'v-menu-collapse-transition': {
        functional: true,
        render(createElement, context) {
          const data = {
            props: {
              mode: 'out-in',
            },
            on: {
              beforeEnter(el) {
                el.style.opacity = 0.2;
              },

              enter(el) {
                addClass(el, 'v-opacity-transition');
                el.style.opacity = 1;
              },

              afterEnter(el) {
                removeClass(el, 'v-opacity-transition');
                el.style.opacity = '';
              },

              beforeLeave(el) {
                if (!el.dataset) el.dataset = {};

                if (hasClass(el, 'v-side-menu--collapse')) {
                  removeClass(el, 'v-side-menu--collapse');
                  el.dataset.oldOverflow = el.style.overflow;
                  el.dataset.scrollWidth = el.scrollWidth;
                  addClass(el, 'v-side-menu--collapse');
                }

                el.style.width = `${el.scrollWidth}px`;
                el.style.overflow = 'hidden';
              },

              leave(el) {
                if (!hasClass(el, 'v-side-menu--collapse')) {
                  addClass(el, 'horizontal-collapse-transition');
                  el.style.width = '64px';
                } else {
                  addClass(el, 'horizontal-collapse-transition');
                  el.style.width = `${el.dataset.scrollWidth}px`;
                }
              },

              afterLeave(el) {
                removeClass(el, 'horizontal-collapse-transition');
                if (hasClass(el, 'v-side-menu--collapse')) {
                  el.style.width = `${el.dataset.scrollWidth}px`;
                } else {
                  el.style.width = '64px';
                }
                el.style.overflow = el.dataset.oldOverflow;
              },
            },
          };
          return createElement('transition', data, context.children);
        },
      },
    },

    props: {
      defaultActive: {
        type: String,
        default: '',
      },
      defaultOpeneds: Array,
      uniqueOpened: Boolean,
      router: Boolean,
      collapse: Boolean,
    },
    data() {
      return {
        activeIndex: this.defaultActive,
        openedMenus: this.defaultOpeneds ? this.defaultOpeneds.slice(0) : [],
        items: {},
        submenus: {},
      };
    },
    watch: {
      defaultActive(value) {
        const item = this.items[value];
        if (item) {
          this.activeIndex = item.index;
          this.initOpenedMenu();
        } else {
          this.activeIndex = '';
        }
      },
      defaultOpeneds(value) {
        this.openedMenus = value;
      },
      collapse(value) {
        if (value) this.openedMenus = [];
      },
    },
    methods: {
      addItem(item) {
        this.$set(this.items, item.index, item);
      },
      removeItem(item) {
        delete this.items[item.index];
      },
      addSubmenu(item) {
        this.$set(this.submenus, item.index, item);
      },
      removeSubmenu(item) {
        delete this.submenus[item.index];
      },
      openMenu(index, indexPath) {
        const openedMenus = this.openedMenus;
        if (openedMenus.indexOf(index) !== -1) return;

        if (this.uniqueOpened) {
          this.openedMenus = openedMenus.filter(_index => indexPath.indexOf(_index) !== -1);
        }
        this.openedMenus.push(index);
      },
      closeMenu(index) {
        this.openedMenus.splice(this.openedMenus.indexOf(index), 1);
      },
      handleSubmenuClick(submenu) {
        const { index, indexPath } = submenu;
        const isOpened = this.openedMenus.indexOf(index) !== -1;

        if (isOpened) {
          this.closeMenu(index);
          this.$emit('close', index, indexPath);
        } else {
          this.openMenu(index, indexPath);
          this.$emit('open', index, indexPath);
        }
      },
      handleItemClick(item) {
        const { index, indexPath } = item;
        this.activeIndex = item.index;
        this.$emit('select', index, indexPath, item);

        if (this.router) {
          this.routeToItem(item);
        }
      },
      initOpenedMenu() {
        const activeItem = this.items[this.activeIndex];
        if (!activeItem) return;

        const indexPath = activeItem.indexPath;

        indexPath.forEach((index) => {
          const submenu = this.submenus[index];
          if (submenu) {
            this.openMenu(index, submenu.indexPath);
          }
        });
      },
      routeToItem(item) {
        const route = item.route || item.index;
        try {
          this.$router.push(route);
        } catch (e) {
          console.error(e);
        }
      },
      setMenuActive(index) {
        this.activeIndex = index;
      },
    },
    mounted() {
      this.initOpenedMenu();
      this.$on('item-click', this.handleItemClick);
      this.$on('submenu-click', this.handleSubmenuClick);
    },
  };
</script>
